package ren.nearby.lib.utils;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.text.TextUtils;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Created by Administrator on 2017/12/6 0006.
 */

public class SecuritySharedPreference implements SharedPreferences {
    private SharedPreferences mSharedPreferences;
    private static final String TAG = SecuritySharedPreference.class.getName();
    private Context mContext;

    public SecuritySharedPreference(Context context, String name, int mode) {
        mContext = context;
        if (TextUtils.isEmpty(name)) {
            mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
        } else {
            mSharedPreferences = context.getSharedPreferences(name, mode);
        }
    }

    @Override
    public Map<String, ?> getAll() {
        final Map<String, ?> encrypMap = mSharedPreferences.getAll();
        final Map<String, String> decryptMap = new HashMap<>();
        for (Map.Entry<String, ?> entryp : encrypMap.entrySet()) {
            Object cipherText = entryp.getValue();
            if (cipherText != null) {
                decryptMap.put(entryp.getKey(), entryp.getValue().toString());
            }
        }
        return decryptMap;
    }

    /**
     * 加密
     *
     * @param plaiText
     * @return
     */
    private String encryptPreference(String plaiText) {
        return EncryptUtil.getInstance(mContext).encrypt(plaiText);
    }

    /**
     * 解密
     *
     * @param plaiText
     * @return
     */
    private String decryptPreference(String plaiText) {
        return EncryptUtil.getInstance(mContext).decrypt(plaiText);
    }

    @Override
    public int getInt(String key, int defValue) {
        final String encryptValue = mSharedPreferences.getString(encryptPreference(key), null);
        if (encryptValue == null) {
            return defValue;
        }
        return Integer.parseInt(decryptPreference(encryptValue));
    }

    @Override
    public float getFloat(String key, float defValue) {
        final String encryptValue = mSharedPreferences.getString(encryptPreference(key), null);
        if (encryptValue == null) {
            return defValue;
        }
        return Float.parseFloat(decryptPreference(encryptValue));
    }

    @Override
    public long getLong(String key, long defValue) {
        final String encryptValue = mSharedPreferences.getString(encryptPreference(key), null);
        if (encryptValue == null) {
            return defValue;
        }
        return Long.parseLong(decryptPreference(encryptValue));
    }

    @Nullable
    @Override
    public String getString(String key, @Nullable String defValue) {
        final String encrytValue = mSharedPreferences.getString(encryptPreference(key), null);
        return encrytValue == null ? defValue : decryptPreference(encrytValue);
    }

    @Nullable
    @Override
    public Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
        final Set<String> encryptSet = mSharedPreferences.getStringSet(encryptPreference(key), null);
        if (encryptSet == null) {
            return defValues;
        }
        final Set<String> decryptSet = new HashSet<>();
        for (String encryptValue : encryptSet) {
            decryptSet.add(decryptPreference(encryptValue));
        }
        return decryptSet;
    }

    @Override
    public boolean getBoolean(String key, boolean defValue) {
        final String encryptValue = mSharedPreferences.getString(encryptPreference(key), null);
        if (encryptValue == null) {
            return defValue;
        }
        return Boolean.parseBoolean(decryptPreference(encryptValue));
    }

    @Override
    public Editor edit() {
        return new SecurityEditor();
    }

    @Override
    public boolean contains(String key) {
        return mSharedPreferences.contains(encryptPreference(key));
    }

    @Override
    public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
        mSharedPreferences.registerOnSharedPreferenceChangeListener(listener);
    }

    @Override
    public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
        mSharedPreferences.unregisterOnSharedPreferenceChangeListener(listener);
    }

    final class SecurityEditor implements Editor {
        private Editor mEditor;

        private SecurityEditor() {
            mEditor = mSharedPreferences.edit();
        }

        @Override
        public Editor putString(String key, @Nullable String value) {
            mEditor.putString(encryptPreference(key), encryptPreference(key));
            return this;
        }

        @Override
        public Editor putStringSet(String key, @Nullable Set<String> values) {
            final Set<String> encryptSet = new HashSet<>();
            for (String value : values) {
                encryptSet.add(encryptPreference(value));
            }
            mEditor.putStringSet(encryptPreference(key), encryptSet);
            return this;
        }

        @Override
        public Editor putInt(String key, int value) {
            mEditor.putString(encryptPreference(key), encryptPreference(Integer.toString(value)));
            return this;
        }

        @Override
        public Editor putLong(String key, long value) {
            mEditor.putString(encryptPreference(key), encryptPreference(Long.toString(value)));
            return this;
        }

        @Override
        public Editor putFloat(String key, float value) {
            mEditor.putString(encryptPreference(key), encryptPreference(Float.toString(value)));
            return this;
        }

        @Override
        public Editor putBoolean(String key, boolean value) {
            mEditor.putString(encryptPreference(key), encryptPreference(Boolean.toString(value)));
            return this;
        }

        @Override
        public Editor remove(String key) {
            mEditor.remove(encryptPreference(key));
            return this;
        }

        @Override
        public Editor clear() {
            mEditor.clear();
            return this;
        }

        @Override
        public boolean commit() {
            return mEditor.commit();
        }

        @Override
        public void apply() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
                mEditor.apply();
            } else {
                commit();
            }
        }
    }

}
